package com.ly.aidlpratice.handwritten

import android.os.*
import com.ly.aidlpratice.bean.Book
import com.ly.aidlpratice.util.logDebug
import com.ly.aidlpratice.util.logError

class ServerBookManager : Binder(), IBookInterface {

    private val mTag: String by lazy { this::class.java.simpleName }

    private val mBookMap by lazy {
        val map = HashMap<Int, Book>()
        map[3000] = Book("Web从入门到精通", 3000, 54f)
        map
    }

    private val mBookList by lazy {
        val list = ArrayList<Book>()
        list.add(Book("Web从入门到精通", 3000, 40f))
        list
    }

    private val mIBookCallbackList: RemoteCallbackList<IBookCallback> =
        RemoteCallbackList<IBookCallback>()

    override fun asBinder(): IBinder {
        return this
    }

    override fun getBook(): Book {
        synchronized(this) {
            printThreadLog("getBook")
            return mBookList[0]
        }
    }

    override fun getAllBook(): List<Book> {
        synchronized(this) {
            printThreadLog("getAllBook")
            return mBookList
        }
    }

    override fun isContainBook(name: String): Boolean {
        synchronized(this) {
            printThreadLog("isContainBook")
            ///此处线程睡眠8s，这种情况，客户端在主线程调用该方法，就会出现掉帧情况
            Thread.sleep(8000L)

            for (book in mBookList) {
                if (book.name.equals(name))
                    return true
            }

            return false
        }
    }

    override fun updateBookPrice(code: Int, price: Float) {
        synchronized(this) {
            printThreadLog("updateBookPrice")
            val book = mBookMap[code]
            book?.also {
                it.price = price
                callback(it)
            }
        }
    }

    override fun getBookPrice(code: Int): Float {
        synchronized(this) {
            printThreadLog("getBookPrice")
            ///此处线程睡眠8s，这种情况，客户端在主线程调用该方法，就会出现掉帧情况
            Thread.sleep(8000L)
            val book = mBookMap[code]
            book?.also {
                return it.price
            }

            return -1f
        }
    }

    override fun insertBook(book: Book) {
        synchronized(this) {
            printThreadLog("insertBook")
            mBookList.add(book)
        }
    }

    override fun insertBookList(list: List<Book>) {
        synchronized(this) {
            printThreadLog("insertBookList")
            mBookList.addAll(list)
        }
    }

    override fun getBookMap(): Map<*, *> {
        synchronized(this) {
            printThreadLog("getBookMap")
            return mBookMap
        }
    }

    override fun insertBookMap(map: Map<*, *>) {
        synchronized(this) {
            printThreadLog("insertBookMapInout")
            mBookMap.putAll(map as Map<out Int, Book>)
        }
    }

    override fun registerCallback(callback: IBookCallback) {
        val result = mIBookCallbackList.register(callback)
        printThreadLog("registerCallback", msg = if (result) "success" else "fail")
    }

    override fun unregisterCallback(callback: IBookCallback) {
        val result = mIBookCallbackList.unregister(callback)
        printThreadLog("unregisterCallback", msg = if (result) "success" else "fail")
    }

    private fun callback(book: Book) {
        val length = mIBookCallbackList.beginBroadcast()
        for (i in 0 until length) {
            try {
                mIBookCallbackList.getBroadcastItem(i).callback(book)
            } catch (e: Exception) {
                logError(mTag, e)
            }
        }
        mIBookCallbackList.finishBroadcast()
    }

    private fun printThreadLog(funcName: String, msg: String = "") {
        logDebug(mTag, "[$funcName][thread.name=${Thread.currentThread().name}]")
    }

    override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
        when (code) {
            INTERFACE_TRANSACTION -> {
                reply?.writeString(BOOK_INTERFACE_TOKEN)
                return true
            }
            TRANSACTION_GET_BOOK -> {
                data.enforceInterface(BOOK_INTERFACE_TOKEN)
                val book = getBook()
                reply?.also {
                    it.writeInt(1)
                    book.writeToParcel(it, Parcelable.PARCELABLE_WRITE_RETURN_VALUE)
                }
                return true
            }
            TRANSACTION_GET_ALL_BOOK -> {
                data.enforceInterface(BOOK_INTERFACE_TOKEN)
                val list = getAllBook()
                reply?.also {
                    reply.writeTypedList(list)
                }
                return true
            }
            TRANSACTION_IS_CONTAIN_BOOK -> {
                data.enforceInterface(BOOK_INTERFACE_TOKEN)
                data.readString()?.also {
                    val result = isContainBook(it)
                    reply?.writeInt(if (result) 1 else 0)
                }
                return true
            }
            TRANSACTION_UPDATE_BOOK_PRICE -> {
                data.enforceInterface(BOOK_INTERFACE_TOKEN)
                val code = data.readInt()
                val price = data.readFloat()
                updateBookPrice(code, price)
                return true
            }
            TRANSACTION_GET_BOOK_PRICE -> {
                data.enforceInterface(BOOK_INTERFACE_TOKEN)
                val code = data.readInt()
                val price = getBookPrice(code)
                reply?.writeFloat(price)
                return true
            }
            TRANSACTION_INSERT_BOOK -> {
                data.enforceInterface(BOOK_INTERFACE_TOKEN)
                val book = Book.CREATOR.createFromParcel(data)
                insertBook(book)
                return true
            }
            TRANSACTION_INSERT_BOOK_LIST -> {
                data.enforceInterface(BOOK_INTERFACE_TOKEN)
                val list = ArrayList<Book>()
                data.readTypedList(list, Book.CREATOR)
                insertBookList(list)
                return true
            }
            TRANSACTION_GET_BOOK_MAP -> {
                data.enforceInterface(BOOK_INTERFACE_TOKEN)
                val map = getBookMap()
                reply?.also {
                    reply.writeInt(1)
                    reply.writeMap(map)
                }
                return true
            }
            TRANSACTION_INSERT_BOOK_MAP -> {
                data.enforceInterface(BOOK_INTERFACE_TOKEN)
                data.readHashMap(javaClass.classLoader)?.also {
                    insertBookMap(it)
                }
                return true
            }
            TRANSACTION_REGISTER_CALLBACK -> {
                data.enforceInterface(BOOK_INTERFACE_TOKEN)
                val binder = data.readStrongBinder()
                registerCallback(ServerBookCallback(binder))
                return true
            }
            TRANSACTION_UNREGISTER_CALLBACK -> {
                data.enforceInterface(BOOK_INTERFACE_TOKEN)
                val binder = data.readStrongBinder()
                unregisterCallback(ServerBookCallback(binder))
                return true
            }
        }
        return super.onTransact(code, data, reply, flags)
    }
}